package com.runa.monitor.platinterface.netservice.equipment;

import com.alibaba.fastjson.JSON;
import com.runa.monitor.comm.dto.Archive;
import com.runa.monitor.comm.dto.Node;
import com.runa.monitor.comm.entity.CommMeter;
import com.runa.monitor.platinterface.backwork.function.TaskFunction;
import com.runa.monitor.platinterface.backwork.impl.RccTaskFunction;
import com.runa.monitor.platinterface.backwork.impl.SelfTaskFunction;
import com.runa.monitor.platinterface.dispatch.conn.gen.RunaEquArchive;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.monitor.platinterface.platService.RepositoryService;
import com.runa.persistence.util.LogUtil;
import com.runa.persistence.util.SpringContextUtil;
import com.runa.protocol.dto.DtuHDRequestData;
import com.runa.protocol.util.ByteUtil;
import com.runa.rccprotocol.dto.ConcentratorRequestDataProxy;
import com.runa.rccprotocol.dto.equdata.EquData;
import com.runa.rccprotocol.dto.langkabo.LangKaBoEquRequestData;
import com.runa.rccprotocol.dto.param.ExtendParam;
import com.runa.rccprotocol.dto.runa.RunaDeviceRequestData;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author diandian
 * @Date 2022/5/14 14:59
 */
@Slf4j
public class LangKaBoDriver extends NetEqu<String> {

    private final String id;

    private final String model;

    private final Map<Integer, String> valveIdxSerial = new HashMap<>();

    public LangKaBoDriver(String id, String serial, String model, Integer timeout) {
        super(serial, timeout);
        this.id = id;
        this.maxRetry = 1;
        this.model = model;
    }


    public void changeAddress(String fmuSerial, String ip, Integer port) {
        LangKaBoEquRequestData concentratorRequestData = new LangKaBoEquRequestData(serial());
        concentratorRequestData.changeAddress(fmuSerial, ip, port);
        concentratorRequestData.setHaveResult(false);
        super.sendRequest(concentratorRequestData, null);
    }


    private void readHouseValve(List<Node> hValves, TaskFunction function) {
        for (Node node : hValves) {
            String serial = node.getSerial();
            LangKaBoEquRequestData concentratorRequestData = new LangKaBoEquRequestData(serial());
            if ("Lcm200-d".equals(model)) {
                concentratorRequestData.readValve188(serial);
            } else {
                concentratorRequestData.readHouseValve(serial);
            }
            concentratorRequestData.setRemain(Collections.singletonList(node));
            super.sendRequest(concentratorRequestData, function);
        }
    }

    private void readHouseMeter(List<Node> hMeters, TaskFunction function) {
        for (Node node : hMeters) {
            try {
                LogUtil.info(serial(), "抄表: {}", JSON.toJSONString(node));
                String serial = node.getSerial();
                LangKaBoEquRequestData concentratorRequestData = new LangKaBoEquRequestData(serial());
                if ("Lcm200-d".equals(model)) {
                    concentratorRequestData.readHeatMeter188(serial);
                } else {
                    concentratorRequestData.readHeatMeter(serial);
                }
                concentratorRequestData.setRemain(Collections.singletonList(node));
                super.sendRequest(concentratorRequestData, function);
            } catch (Exception e) {
                LogUtil.info(serial(), "异常: {} {}", JSON.toJSONString(node), e);
            }
        }
    }

    public static void main(String[] args) {
//        LangKaBoEquRequestData concentratorRequestData = new LangKaBoEquRequestData("53020001");
        LangKaBoEquRequestData concentratorRequestData = new LangKaBoEquRequestData("53020317");
//        concentratorRequestData.setNodeEquArchive("140420287","汇中");
//        concentratorRequestData.setNodeEquArchive("140429289","汇中");
//        concentratorRequestData.setNodeEquArchive("21784033","瑞纳");
//        concentratorRequestData.setNodeEquArchive("21126922","测试");
//        concentratorRequestData.readHeatMeter("21784033");
//        concentratorRequestData.readHeatMeter("22760609");
        concentratorRequestData.readElectric();
        byte[] data = concentratorRequestData.getData();
        String s = ByteUtil.byteToHexString(data, 0, data.length);
        s=hexFormat(s);
        System.out.println(s);
    }

    private static String hexFormat(String s) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < s.length(); i += 2) {
            stringBuilder.append(s, i, i + 2).append(" ");
        }
        return stringBuilder.substring(0,stringBuilder.length()-1);
    }

    @Override
    public void setNodeEquArchive(List<Archive> archives, TaskFunction function) {
        if (!online()) {
            function.doApply(CommStatus.OffLine,
                    archives.stream().map(archive ->
                    ((RunaEquArchive) archive).getIndex())
                            .collect(Collectors.toList()));
            return;
        }
        RepositoryService repositoryService = SpringContextUtil.getBean(RepositoryService.class);
        for (Archive archive : archives) {
            LangKaBoEquRequestData requestData = new LangKaBoEquRequestData(serial());
            RunaEquArchive meterArchive = (RunaEquArchive) archive;
            CommMeter commMeter = repositoryService.getCommMeterByNodeSerialForNetEqu(meterArchive.getSerial(), this.id);
            requestData.setNodeEquArchive(meterArchive.getSerial(), commMeter.getFactoryName());
            log.debug("琅卡博下发表号：{} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
            requestData.setRemain(Collections.singletonList(meterArchive.getIndex()));
            sendRequest(requestData, function);
        }
    }

    public void readElectricityMeter() {
        if (!"Lcm200-d".equals(model)) {
            LangKaBoEquRequestData requestData = new LangKaBoEquRequestData(serial());
            requestData.readElectric();
            sendRequest(requestData, new SelfTaskFunction(serial()));
        }
    }

    @Override
    public void clearNodeEquArchive(TaskFunction function) {
    }


    private void readBuildValve(List<Node> valves, TaskFunction function) {
        for (Node valve : valves) {
            LangKaBoEquRequestData requestData = new LangKaBoEquRequestData(serial());
            int slave = Integer.parseInt(valve.getSerial().substring(valve.getSerial().length() - 3));
            slave = slave > 246 ? Integer.parseInt(valve.getSerial().substring(valve.getSerial().length() - 2)) : slave;
            valveIdxSerial.put(slave, valve.getSerial());
            requestData.readBuildValve(slave, "LCCV".equals(valve.getModel()), valve.getSerial());
            requestData.setRemain(Collections.singletonList(valve));
            sendRequest(requestData, function);
        }
    }

    @Override
    public void readNodeEqu(List<Node> nodeList, TaskFunction function, EquData.EquDataType type) {
        //如果集中器不在线直接触发离线回调
        if (!online()) {
            function.doApply(CommStatus.OffLine, nodeList);
            return;
        }
//        List<Node> nodes = filterNodes(nodeSerial, function, type);
        switch (type) {
            case METER:
                readHouseMeter(nodeList, function);
                break;
            case VALVE:
                readHouseValve(nodeList, function);
                break;
            case PUBLIC_UNIT:
                readBuildValve(nodeList, function);
                break;
            default:
        }
    }


    @Override
    public void valveOnOffControl(List<Node> valves, boolean ifLock, Integer opening, TaskFunction function) {
        if (!online()) {
            function.doApply(CommStatus.OffLine, valves);
            return;
        }
        LangKaBoEquRequestData requestData;
        for (Node valve : valves) {
            if (valve != null) {
                requestData = new LangKaBoEquRequestData(serial());
                requestData.setValve188Open(valve.getSerial(), opening, ifLock);
                requestData.setRemain(valve);
                sendRequest(requestData, function);
            }
        }
    }

    @Override
    public void readNodeRecord(List<Integer> indexes, TaskFunction function) {

    }

    @Override
    public void sentPublicUnitRecord(List<Node> valveSerial, Integer model, Map param, TaskFunction function) {
        LangKaBoEquRequestData requestData;
        for (Node unit : valveSerial) {
            if (unit != null) {
                switch (model) {
                    case 1:
                        requestData = new LangKaBoEquRequestData(serial());
                        requestData.sentBuildValveModel(unit.getSerial(),
                                "LCCV".equals(unit.getModel()), true);
                        sendRequest(requestData, new RccTaskFunction.EmptyTask(function.getPriority()));
                        requestData.sentBuildValveOpen(unit.getSerial(),
                                "LCCV".equals(unit.getModel()),
                                (int) Float.parseFloat(param.get("targetValue").toString()));
                        requestData.setRemain(unit);
                        sendRequest(requestData, function);
                        break;
                    case 2:
                    case 3:
                    case 4:
                        break;
                    default:
                }
            }
        }
    }

    @Override
    public void sentPublicUnitModel(List<Node> valve, boolean model, TaskFunction function) {

    }

    @Override
    public void sentExtendParam(ExtendParam param, TaskFunction function) {

    }

    @Override
    public void readPublicUnitRecord(Node valve, Integer model, TaskFunction function) {

    }

    @Override
    public void readPublicUnitAndMeter(Node valve, Node meter, TaskFunction function) {

    }

}
